#include <iostream>
#include <array>
#include <tuple>
#include <string>
#include <sstream>

using namespace std;

namespace TraitsLearn1 {

    //template 、typename 基本概念
    template <typename T> //typename只能用于模板的定义中
    int compare(const T& v1, const T& v2)
    {
        if (v1 == v2)return 0;
        return (v1 < v2) ? -1 : 1;
    }
    template <class T>
    int compare1(const T& v1, const T& v2)
    {
        if (v1 == v2)return 0;
        return(v1 < v2) ? -1 : 1;
    }
    template <class T>
    void foo() {
    //    T::iterator* iter;  //需要等到实例化时期才能确定是变量还是类型，存在歧义 。  如果iter是一个全局变量，则变成了：某变量*iter ，一个无意义的定义，产生BUG
        typename T::iterator* iter1;  //告诉编译器T::iterator是类型而不是变量，只需用typename修饰。不需要等到实例化时才能确定
        // ...
    }

    //第一步：定义这个策略Trait，这个策略实现【char】与【非char】的判断。
    template<typename T>
    class IsChar
    {
    public:
        static const bool yes = false;
    };

    template<>
    class IsChar<char>
    {
    public:
        static const bool yes = true;
    };


    //第二步：提升，根据策略实现不同反应。
    template<bool c, typename T>
    class Decision;

    template<typename T>
    class Decision<true, T>
    {
    public:
        static void print(T a) { cout << a << "--char" << endl; };
    };

    template<typename T>
    class Decision<false, T>
    {
    public:
        static void print(T a) { cout << a << "--not_char" << endl; };
    };

    //第三步：封装提升，只留一个接口。
    template<typename T>
    void ppt(T a)
    {
        Decision<IsChar<T>::yes, T>::print(a);
    }

    template<typename T>
    void ppt1(T a)
    {
        if(IsChar<T>::yes)
            cout << a << "--char--ppt1" << endl;
        else
            cout << a << "--not_char--ppt1" << endl;
    }

    struct A 
    {
        int a;
        friend ostream& operator<<(ostream& out, A s); //不重载就无法编译Decision的print方法
    };
    ostream& operator<<(ostream& out, A s)
    {
        out << s.a ;
        return out;
    }
    int main()
    {
        int v1 = 1, v2 = 2;
        int ret = compare(v1, v2);
        int* pv1 = NULL, * pv2 = NULL;
        ret = compare(pv1, pv2);
        ret = compare1(pv1, pv2);

        //测试一下
        ppt(1);
        ppt('c');
        ppt("abc");

        A a1;
        a1.a = 10;
        ppt(a1);

        ppt1(1);
        ppt1('c');

        return 0;
    }

    
}
